home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / languages / fpl-v115.lha / FPL / src / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-28  |  27.4 KB  |  1,006 lines

  1. /******************************************************************************
  2.  *                   FREXX PROGRAMMING LANGUAGE                  *
  3.  ******************************************************************************
  4.  
  5.  hash.c
  6.  
  7.  Functions for FPL hash tables and sorting!
  8.  
  9.  *****************************************************************************/
  10.  
  11. /************************************************************************
  12.  *                                                                      *
  13.  * fpl.library - A shared library interpreting script langauge.         *
  14.  * Copyright (C) 1992-1994 FrexxWare                                    *
  15.  * Author: Daniel Stenberg                                              *
  16.  *                                                                      *
  17.  * This program is free software; you may redistribute for non          *
  18.  * commercial purposes only. Commercial programs must have a written    *
  19.  * permission from the author to use FPL. FPL is *NOT* public domain!   *
  20.  * Any provided source code is only for reference and for assurance     *
  21.  * that users should be able to compile FPL on any operating system     *
  22.  * he/she wants to use it in!                                           *
  23.  *                                                                      *
  24.  * You may not change, resource, patch files or in any way reverse      *
  25.  * engineer anything in the FPL package.                                *
  26.  *                                                                      *
  27.  * This program is distributed in the hope that it will be useful,      *
  28.  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
  29.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
  30.  *                                                                      *
  31.  * Daniel Stenberg                                                      *
  32.  * Ankdammsgatan 36, 4tr                                                *
  33.  * S-171 43 Solna                                                       *
  34.  * Sweden                                                               *
  35.  *                                                                      *
  36.  * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
  37.  *                                                                      *
  38.  ************************************************************************/
  39.  
  40. #ifdef AMIGA
  41. #include <exec/types.h>
  42. #include <proto/exec.h>
  43. #include <dos.h>
  44. #else
  45. #include <stdio.h>
  46. #endif
  47. #include "script.h"
  48. #include "debug.h"
  49. #include <limits.h>
  50.  
  51. #ifdef DEBUG
  52. #include <stdio.h>
  53. #endif
  54.  
  55. static ReturnCode REGARGS AddIdentifier(struct Data *, struct Identifier *);
  56. static ReturnCode INLINE InitHash(struct Data *);
  57. static unsigned long INLINE Gethash(char *);
  58. static void * INLINE Init(struct Data *, long ASM (*)(AREG(0) void *), unsigned long *);
  59. static ReturnCode REGARGS SetTags(struct Data *, unsigned long *);
  60. static ReturnCode INLINE Hijack(struct Data *, struct Identifier *);
  61.  
  62. /**********************************************************************
  63.  *
  64.  * int fplAddFunction();
  65.  *
  66.  * User frontend to AddIdentifier().
  67.  *
  68.  *****/
  69.  
  70.  
  71. ReturnCode PREFIX
  72.   fplAddFunction(AREG(0) struct Data *scr,      /* pointer to struct Data */
  73.          AREG(1) char *name,     /* name of function */
  74.          DREG(0) long ID,     /* function ID */
  75.          DREG(1) char rtrn,      /* return type */
  76.          AREG(2) char *format,   /* format string */
  77.          AREG(3) unsigned long *tags) /* taglist pointer */
  78. {
  79.   ReturnCode ret;
  80.   struct Identifier *ident;
  81. #ifdef DEBUGMAIL
  82.   DebugMail(scr, MAIL_FUNCTION, 500, "fplAddFunction");
  83. #endif
  84.   if(!scr)
  85.     return(FPLERR_ILLEGAL_ANCHOR);
  86.  
  87.   ident=MALLOCA(sizeof(struct Identifier));
  88.   if(!ident)
  89.     return(FPLERR_OUT_OF_MEMORY);
  90.  
  91.   memset(&ident->data.external, 0, sizeof(struct ExternalFunction));
  92.   while(tags && *tags) {
  93.     switch(*tags++) {
  94.     case FPLTAG_USERDATA:
  95.       ident->data.external.data=(void *)*tags;
  96.       break;
  97.     case FPLTAG_FUNCTION:
  98.       ident->data.external.func=(long (*)(void *))*tags;
  99.       break;
  100.     }
  101.     tags++; /* next! */
  102.   }
  103.  
  104.   ident->name = name;
  105.   ident->data.external.ID = ID;
  106.   ident->data.external.ret = rtrn;
  107.   ident->data.external.format = format;
  108.   ident->flags = FPL_EXTERNAL_FUNCTION|FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL;
  109.   ident->file = "<user>"; /* User added! */
  110.   ident->func = NULL; /* everywhere! */
  111.   ident->level = 0;
  112.  
  113.   CALL(AddIdentifier(scr, ident));
  114.   return(FPL_OK);
  115. }
  116.  
  117. /**********************************************************************
  118.  *
  119.  * int fplDelFunction();
  120.  *
  121.  * User frontend to DelIdentifier().
  122.  *
  123.  ******/
  124.  
  125. ReturnCode PREFIX fplDelFunction(AREG(0) struct Data *scr,
  126.                  AREG(1) char *name)
  127. {
  128.   ReturnCode ret;
  129. #ifdef DEBUGMAIL
  130.   DebugMail(scr, MAIL_FUNCTION, 500, "fplDelFunction");
  131. #endif
  132.   if(!scr)
  133.     return(FPLERR_ILLEGAL_ANCHOR);
  134.   CALL(DelIdentifier(scr, name, NULL));
  135.   return(FPL_OK);
  136. }
  137.  
  138.  
  139. /**********************************************************************
  140.  *
  141.  * int AddVar();
  142.  *
  143.  * Frontend to the AddIdentifier function.
  144.  *
  145.  * This routine adds a member to the linked list of local variable names.
  146.  * That list exists to enable easy and fast removal of local variables
  147.  * when leaving a block within which local variables has been declared!
  148.  *
  149.  * Make sure that the name member data is static as long we need this list
  150.  * cause this routine doesn't copy that name, simply points to it!
  151.  *
  152.  *****/
  153.  
  154.  
  155. ReturnCode REGARGS
  156. AddVar(struct Data *scr, /* pointer to struct Data */
  157.        struct Identifier *ident,/* identifier struct pointer */
  158.        struct Local **local)
  159. {
  160.   ReturnCode ret;
  161.   struct Local *temp;
  162.   if(ret=AddIdentifier(scr, ident))
  163.     ;
  164.   else {
  165.     GETMEM(temp, sizeof(struct Local));  
  166.     temp->next=*local;
  167.     temp->ident=ident;
  168.     *local=temp;
  169.   }
  170.   return(ret);
  171. }
  172.  
  173. /**********************************************************************
  174.  *
  175.  * AddLevel();
  176.  *
  177.  * This function adds a NULL-name in the local symbol list to visualize
  178.  * the beginning of a new variable level!
  179.  *
  180.  *******/
  181.  
  182. ReturnCode REGARGS
  183. AddLevel(struct Data *scr)
  184. {
  185.   struct Local *temp;
  186.   GETMEM(temp, sizeof(struct Local));  
  187.   temp->next=scr->locals;
  188.   temp->ident=NULL;
  189.   scr->locals=temp;
  190.   return(FPL_OK);
  191. }
  192.  
  193.  
  194. /**********************************************************************
  195.  *
  196.  * int DelLocalVar()
  197.  *
  198.  * This routine deletes all members to the linked list of local variable
  199.  * names. Call this routine every time you leave a local level. Deletes
  200.  * all variables and the following NULL name!
  201.  *
  202.  *****/
  203.  
  204. ReturnCode REGARGS
  205. DelLocalVar(struct Data *scr,
  206.             struct Local **local)
  207. {
  208.   /* This removes only all listed symbols! */
  209.   struct Identifier *ident;
  210.   while(*local) {
  211.     struct Local *temp=(*local)->next;
  212.     ident=(*local)->ident;
  213.     FREE(*local);
  214.     *local=temp;
  215.     if(ident)
  216.       DelIdentifier(scr, NULL, ident); /* delete it for real */
  217.     else
  218.       break;
  219.   }
  220.   return(FPL_OK);
  221. }
  222.  
  223.  
  224. /**********************************************************************
  225.  *
  226.  * int AddIdentifier()
  227.  *
  228.  * This function adds the function to the hash table according to all
  229.  * parameters.
  230.  *
  231.  * If the hash member of the Data structure is NULL, the hash table
  232.  * will be inited. No not init the hash list if you don't have to cause
  233.  * that sure is a peep hole in the performance...
  234.  *
  235.  *******/
  236.  
  237. static ReturnCode REGARGS
  238. AddIdentifier(struct Data *scr,
  239.               struct Identifier *ident)
  240. {
  241.   unsigned long hash;       /* hash number of the identifier */
  242.   struct Identifier **add;  /* where to store the pointer to this identifier */
  243.   struct Identifier *prev=NULL; /* pointer to previous hash structure */
  244.   struct Identifier *next;  /* pointer to next hash structure */
  245.   ReturnCode ret;
  246.   hash=Gethash(ident->name);
  247.   
  248.   add=(struct Identifier **)&scr->hash[hash % scr->hash_size];
  249.   while(*add) {
  250.     if((*add)->hash==hash) {
  251.       /* they were identical */
  252.       if(ident->flags&FPL_FUNCTION &&
  253.      !strcmp((*add)->name, ident->name) &&
  254. /*
  255.   PREV STOOPID WAY:
  256.      (!ident->file || !strcmp(ident->file, (*add)->file))) { */
  257.  
  258.      (ident->flags&FPL_EXPORT_SYMBOL || !strcmp(ident->file, (*add)->file))) {
  259.     /* if it's a function, warning!!! */
  260.     CALL(Warn(scr, FPLERR_IDENTIFIER_USED));
  261.     DelIdentifier(scr, NULL, *add); /* remove it! */
  262.     /* we must call this routine again to re-read the lists with
  263.        the function removed! */
  264.     ret=AddIdentifier(scr, ident);
  265.     return(ret);
  266.       } else
  267.     /* add it here! */
  268.     break; 
  269.     } else if((*add)->hash>hash) {
  270.       /* continue search for a place to insert */
  271.       /* 'add' now points to the pointer */
  272.       prev=(*add);
  273.       add=(struct Identifier **)&((*add)->next);
  274.     } else {
  275.       /* insert it here! */
  276.       prev=(*add)->prev;
  277.       break;
  278.     }
  279.   }
  280.  
  281.   next=(*add);
  282.   *add=ident;
  283.   (*add)->hash=hash;
  284.   (*add)->prev=prev;
  285.   (*add)->next=next;
  286.   if(next)
  287.     next->prev=ident;
  288.   return(FPL_OK);
  289. }
  290.  
  291. /**********************************************************************
  292.  *
  293.  * int GetIdentifier();
  294.  *
  295.  * Sets the pointer to the Identifier structure to which the name
  296.  * fits, in the third argument.
  297.  *
  298.  *****/
  299.  
  300. #ifdef DEBUG
  301. int hashed=0;
  302. int max_hashed=0;
  303. #endif
  304.  
  305. ReturnCode REGARGS
  306. GetIdentifier(struct Data *scr,
  307.               char *name,
  308.           struct Identifier **ident)
  309. {
  310.   ReturnCode ret;
  311.   struct Identifier *get;
  312.   unsigned long hash=Gethash(name);
  313.   get=scr->hash[hash%scr->hash_size];
  314. #ifdef DEBUG
  315.   hashed=0;
  316. #endif
  317.   while(get) {
  318.     if(
  319.  
  320.        (get->hash==hash) && 
  321.        /* identical hash value! */
  322.  
  323.        !strcmp(get->name, name) &&
  324.        /* identical name! */
  325.  
  326.        (get->flags&(FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL) ||
  327.         (get->func==scr->func && get->level<=scr->varlevel)) &&
  328.        /* If not global, declared under the *same* function, in this or
  329.       a lower level! */
  330.  
  331.        (get->flags&FPL_EXPORT_SYMBOL || !strcmp(get->file, scr->prog->name))
  332.        /* If not cross-file, the same file! */
  333.  
  334.        ) {
  335.  
  336.       /* this is it! */
  337.       *ident=get;
  338. #ifdef DEBUG
  339.       if(hashed>max_hashed)
  340.     max_hashed=hashed;
  341. #endif
  342.       if(get->flags&FPL_EXTERNAL_VARIABLE) {
  343.     CALL(Hijack(scr, get));
  344.       }
  345.       return(FPL_OK);
  346.     } else if(get->hash<hash)
  347.       /* we've been searching through all possible alternatives! */
  348.       break;
  349. #ifdef DEBUG
  350.     hashed++;
  351. #endif
  352.     get=get->next;
  353.   }    
  354.   *ident=NULL;
  355.   return(FPLERR_IDENTIFIER_NOT_FOUND);
  356. }
  357.  
  358. /**********************************************************************
  359.  *
  360.  * int fplAddFunction();
  361.  *
  362.  * User frontend to AddIdentifier(). New in version 10!
  363.  *
  364.  *****/
  365.  
  366.  
  367. ReturnCode PREFIX
  368.   fplAddVariable(AREG(0) struct Data *scr, /* pointer to struct Data */
  369.          AREG(1) char *name,       /* name of variable */
  370.          DREG(0) long ID,       /* variable ID */
  371.          DREG(1) char type,        /* variable type */
  372.                  AREG(2) void *defvalue,   /* default value */
  373.          AREG(3) unsigned long *tags) /* taglist pointer */
  374. {
  375.   ReturnCode ret;
  376.   struct Identifier *ident;
  377. #ifdef DEBUGMAIL
  378.   DebugMail(scr, MAIL_FUNCTION, 500, "fplAddVariable");
  379. #endif
  380.   if(!scr)
  381.     return(FPLERR_ILLEGAL_ANCHOR);
  382.  
  383.   GETMEMA(ident, sizeof(struct Identifier));
  384.  
  385.   memset(&ident->data.variable, 0, sizeof(struct fplVariable));
  386.  
  387.   ident->name = name;
  388.   ident->data.variable.ID = ID;
  389.   ident->flags = FPL_EXTERNAL_VARIABLE|FPL_GLOBAL_SYMBOL|FPL_EXPORT_SYMBOL|
  390.     (type == FPL_STRARG? FPL_STRING_VARIABLE:FPL_INT_VARIABLE)|
  391.       FPL_READONLY;
  392.   if(type == FPL_INTARG) {
  393.     GETMEM(ident->data.variable.var.val32, sizeof(long));
  394.     ident->data.variable.var.val32[0] = (long) defvalue;
  395.   }
  396.   else
  397.     if(defvalue) {
  398.       register long len = (long)strlen((char *)defvalue);
  399.       if(len) {
  400.         GETMEM(ident->data.variable.var.str, sizeof(struct fplStr *));
  401.         GETMEM(ident->data.variable.var.str[0], len + sizeof(struct fplStr));
  402.         ident->data.variable.var.str[0]->len = len;
  403.         ident->data.variable.var.str[0]->alloc = len;
  404.         memcpy(ident->data.variable.var.str[0]->string, defvalue,
  405.                len);
  406.         ident->data.variable.var.str[0]->string[len] = '\0'; /* Z-terminate */
  407.       }
  408.     }
  409.   ident->file = "<user>"; /* Used added! */
  410.   ident->func = NULL; /* everywhere! */
  411.   ident->level = 0;
  412.  
  413.   CALL(AddIdentifier(scr, ident));
  414.   return(FPL_OK);
  415. }
  416.  
  417. /*************************************************************************
  418.  *
  419.  * Hijack();
  420.  *
  421.  * This function gets called whenever an external variable has been selected
  422.  * by GetIdentifier().
  423.  *
  424.  ******/
  425.  
  426. static ReturnCode INLINE Hijack(struct Data *scr, struct Identifier *ident)
  427. {
  428.   struct fplArgument pass;
  429.   struct fplMsg *msg;
  430.   ReturnCode ret;
  431.  
  432.   memset(&pass, 0, sizeof(struct fplArgument));
  433.   pass.argc=0;
  434.   pass.name=ident->name;
  435.   pass.ID=ident->data.variable.ID;
  436.   pass.key=scr;
  437.   pass.variable = (void *)
  438.     (ident->flags&FPL_STRING_VARIABLE?
  439.      (ident->data.variable.var.str[0]?ident->data.variable.var.str[0]->string:""):
  440.      (void *)ident->data.variable.var.val32[0]);
  441.  
  442.   CALL(InterfaceCall(scr, &pass, scr->function));
  443.   if(ident->flags&FPL_INT_VARIABLE) {
  444.     /*
  445.      * Integer variable!
  446.      */
  447.     CALL(GetMessage(scr, FPLMSG_RETURN_INT, &msg));
  448.     if(msg) {
  449.       ident->data.variable.var.val32[0]=(long)msg->message[0];
  450.       CALL(DeleteMessage(scr, msg));
  451.     }
  452.   } else {
  453.     /*
  454.      * String variable!
  455.      */
  456.     CALL(GetMessage(scr, FPLMSG_RETURN_STRING, &msg));
  457.     if(msg) {
  458.       if(ident->data.variable.var.str[0]) {
  459.     FREEA(ident->data.variable.var.str[0]);
  460.       }
  461.       ident->data.variable.var.str[0]=(struct fplStr *)msg->message[0];
  462.       /*
  463.        * Make the string to be static always!
  464.        */
  465.       SwapMem(scr, ident->data.variable.var.str[0], MALLOC_STATIC);
  466.       DeleteMessage(scr, msg);
  467.     }
  468.   }
  469.   return(FPL_OK);
  470. }
  471.  
  472. /**********************************************************************
  473.  *
  474.  * int InitHash()
  475.  *
  476.  * Initialize the hash table. Simple and quick!
  477.  *
  478.  *****/
  479.  
  480. struct ShitData {
  481.   char *name;
  482.   long ID;
  483.   char ret;
  484.   char *format;
  485. };
  486.  
  487. struct MoreShitData {
  488.   char *name;
  489.   long ID;
  490.   long flags;
  491. };
  492.  
  493. static ReturnCode INLINE InitHash(struct Data *scr)
  494. {
  495.   ReturnCode ret;
  496.   static struct ShitData internal_functions[]={
  497.     {"abs",        FNC_ABS,    'I', "I"},
  498.     {"atoi",        FNC_ATOI,    'I', "S"},
  499.     {"closelib",    FNC_CLOSELIB,    'I', "S"},  /* amiga only */
  500.     {"debug",        FNC_DEBUG,    'I', "i"},
  501.     {"eval",        FNC_EVAL,    'I', "S"},
  502.     {"interpret",    FNC_INTERPRET,    'I', "S"},
  503.     {"itoa",        FNC_ITOA,    'S', "I"},
  504.     {"itoc",        FNC_ITOC,    'S', "I"},
  505.     {"joinstr",        FNC_JOINSTR,    'S', "s>"},
  506.     {"ltostr",        FNC_LTOSTR,    'S', "Ii"},
  507.     {"openlib",        FNC_OPENLIB,    'I', "SI"}, /* amiga only */
  508.     {"sprintf",        FNC_SPRINTF,    'S', "Sa>"},
  509.     {"strcmp",        FNC_STRCMP,    'I', "SS"},
  510.     {"stricmp",        FNC_STRICMP,    'I', "SS"},
  511.     {"strlen",        FNC_STRLEN,    'I', "S"},
  512.     {"strncmp",        FNC_STRNCMP,    'I', "SSI"},
  513.     {"strnicmp",    FNC_STRNICMP,    'I', "SSI"},
  514.     {"strstr",        FNC_STRSTR,    'I', "SSi"},
  515.     {"stristr",        FNC_STRISTR,    'I', "SSi"},
  516.     {"strtol",        FNC_STRTOL,    'I', "Si"},
  517.     {"substr",        FNC_SUBSTR,    'S', "SII"},
  518.   };
  519.  
  520. /* FPL keywords. "else" is not included (treated special). */
  521.  
  522.   static struct MoreShitData keywords[]={
  523.     {"auto",    CMD_AUTO,    FPL_KEYWORD_DECLARE},
  524.     {"break",    CMD_BREAK,    0},
  525.     {"case",    CMD_CASE,    0},
  526.     {"char",    CMD_INT,    FPL_KEYWORD_DECLARE|FPL_CHAR_VARIABLE},
  527.     {"const",    CMD_CONST,    FPL_KEYWORD_DECLARE},
  528.     {"continue", CMD_CONTINUE,    0},
  529.     {"default",    CMD_DEFAULT,    0},
  530.     {"do",    CMD_DO,        0},
  531.     {"double",    CMD_DOUBLE,    FPL_IGNORE},
  532.     {"enum",    CMD_ENUM,    FPL_IGNORE},
  533.     {"exit",    CMD_EXIT,    0},
  534.     {"export",    CMD_EXPORT,    FPL_KEYWORD_DECLARE},
  535.     {"float",   CMD_FLOAT,    FPL_IGNORE},
  536.     {"for",    CMD_FOR,    0},
  537.     {"if",    CMD_IF,        0},
  538.     {"int",    CMD_INT,    FPL_KEYWORD_DECLARE},
  539.     {"long",    CMD_INT,    FPL_KEYWORD_DECLARE},
  540.     {"register",CMD_REGISTER,    FPL_KEYWORD_DECLARE},
  541.     {"resize",    CMD_RESIZE,    0},
  542.     {"return",    CMD_RETURN,    0},
  543.     {"short",    CMD_INT,    FPL_KEYWORD_DECLARE|FPL_SHORT_VARIABLE},
  544.     {"signed",    CMD_SIGNED,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  545.     {"static",  CMD_STATIC,    FPL_KEYWORD_DECLARE},
  546.     {"string",    CMD_STRING,    FPL_KEYWORD_DECLARE},
  547.     {"struct",  CMD_STRUCT,    FPL_IGNORE},
  548.     {"switch",    CMD_SWITCH,    0},
  549.     {"typedef",    CMD_TYPEDEF,    0},
  550.     {"union",    CMD_UNION,    FPL_IGNORE},
  551.     {"unsigned",CMD_UNSIGNED,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  552.     {"void",    CMD_VOID,    FPL_KEYWORD_DECLARE},
  553.     {"volatile",CMD_VOLATILE,    FPL_KEYWORD_DECLARE|FPL_IGNORE},
  554.     {"while",    CMD_WHILE,    0},
  555.   };
  556.   long i;
  557.   struct Identifier *ident;
  558.   GETMEMA(scr->hash, sizeof(struct Identifier *)* scr->hash_size);
  559.  
  560.   memset((void *)scr->hash, 0, sizeof(struct Identifier *)*scr->hash_size);
  561.   /*
  562.    * The hash table initialization gives us a brilliant chance to bring up
  563.    * the execution speed even more by inserting the few internal functions
  564.    * into this same table. The functions will then act *EXACTLY* the same
  565.    * and we can shorten the code and much easier write internal functions
  566.    * that return strings...
  567.    */
  568.  
  569.   for(i=0; i<sizeof(internal_functions)/sizeof(struct ShitData);i++) {
  570.     GETMEMA(ident, sizeof(struct Identifier));
  571.     ident->name=internal_functions[i].name;
  572.     ident->data.external.ID=internal_functions[i].ID;
  573.     ident->data.external.ret=internal_functions[i].ret;
  574.     ident->data.external.format=internal_functions[i].format;
  575.     ident->flags=FPL_INTERNAL_FUNCTION|FPL_EXPORT_SYMBOL;
  576.     ident->level=0;
  577.     ident->func=NULL; /* all functions */
  578.     ident->file= "<FPL>"; /* internal */
  579.     ret=AddIdentifier(scr, ident);
  580.     if(ret)
  581.       break;
  582.   }
  583.   for(i=0; i<sizeof(keywords)/sizeof(struct MoreShitData);i++) {
  584.     GETMEMA(ident, sizeof(struct Identifier));
  585.     ident->name=keywords[i].name;
  586.     ident->data.external.ID=keywords[i].ID;  /* dirty enum work! */
  587.     ident->flags=FPL_EXPORT_SYMBOL|FPL_KEYWORD|keywords[i].flags;
  588.     ident->level=0;
  589.     ident->func=NULL;  /* all functions */
  590.     ident->file= "<FPL>";  /* internal */
  591.     ret=AddIdentifier(scr, ident);
  592.     if(ret)
  593.       break;
  594.   }
  595.   return(ret);
  596. }
  597.  
  598. /**********************************************************************
  599.  *
  600.  * int Gethash();
  601.  *
  602.  * Return the hash number for the name received as argument.
  603.  *
  604.  *****/
  605.  
  606. static unsigned long INLINE Gethash(char *name)
  607. {
  608.   unsigned long hash=0;
  609.   while(*name)
  610.     hash=(hash<<1)+*name+++(hash&(1<<31)?-2000000000:0);
  611.   return(hash);
  612. }
  613.  
  614. /**********************************************************************
  615.  *
  616.  * void Free();
  617.  *
  618.  * This function frees the resources used by this FPL session.
  619.  *
  620.  ***********/
  621.  
  622. void PREFIX fplFree(AREG(0) struct Data *scr)
  623. {
  624.   struct Data onstack;
  625.   long retval;
  626. #ifdef DEBUGMAIL
  627.   DebugMail(scr, MAIL_FUNCTION, 500, "fplFree");
  628. #endif
  629.   onstack=*scr; /* copy the entire struct */
  630.   scr=&onstack; /* use the `stack-struct' */
  631.   DelProgram(scr, NULL); /* remove all programs from memory, some might be
  632.                 Lock()'ed! */
  633. #ifdef AMIGA /* only amiga supports funclibs! */
  634.   CloseLib(scr, NULL, TRUE, &retval); /* force close of all funclibs */
  635. #endif
  636.   FREEALL();
  637.   FREEALLA();
  638. }
  639.  
  640. /**********************************************************************
  641.  *
  642.  * int DelIdentifier()
  643.  *
  644.  * Delete an identifier from the hash table. Specify 'name' or 'ident'.
  645.  *
  646.  ******/
  647.  
  648. ReturnCode REGARGS
  649. DelIdentifier(struct Data *scr,
  650.               char *name,
  651.           struct Identifier *ident)
  652. {
  653.   ReturnCode ret;
  654.   long i;
  655.   struct fplVariable *var;
  656.  
  657.   if(!ident) {
  658.     /* Get the structure pointer */
  659.     CALL(GetIdentifier(scr, name, &ident));
  660.   }
  661.   
  662.   /* Link the previous member in the list to the next member */
  663.   if(ident->prev)
  664.     /* If there is a previous member */
  665.     ident->prev->next=ident->next;
  666.   else
  667.     /* if this was the first in the list */
  668.     scr->hash[ident->hash%scr->hash_size]=ident->next;
  669.  
  670.   if(ident->next)
  671.     ident->next->prev=ident->prev;
  672.  
  673.   /*
  674.    * If it is any kind of funtion, all the data the pointers points to
  675.    * should (in the specs) be static and should therefore *NOT* be
  676.    * freed here!
  677.    *
  678.    * Notice that even internal functions are possible to remove here...
  679.    */
  680.  
  681.   if(ident->flags & FPL_VARIABLE) {
  682.     /*
  683.      * It's a variable identifier. Free some members:
  684.      */
  685.     
  686.     var=&ident->data.variable;
  687.     
  688.     if(ident->flags & FPL_REFERENCE) {
  689.       /* only keep a reference pointer! */
  690.     }
  691.     else {
  692.       if(ident->flags & FPL_STRING_VARIABLE) {
  693.     /* it's a string array! */
  694.     for(i=0; i<var->size; i++)
  695.       if(var->var.str[i]) {
  696.         FREE_KIND(var->var.str[i]);
  697.       }
  698.       }
  699.       if(var->num)
  700.     FREE_KIND(var->dims);
  701.       FREE_KIND(var->var.val);
  702.     }
  703.   } else if(ident->flags&FPL_INSIDE_FUNCTION &&
  704.             ident->data.inside.format) {
  705.     FREE_KIND(ident->data.inside.format);
  706.   }
  707.   if((ident->flags&FPL_EXTERNAL_FUNCTION)||
  708.      (ident->flags&(FPL_INTERNAL_FUNCTION|FPL_KEYWORD))) {
  709.     /* internal or external function */
  710.     FREEA(ident);
  711.   } else  {
  712.     FREE_KIND(ident->name);
  713.     FREE_KIND(ident);
  714.   }
  715.   return(ret);
  716. }
  717.  
  718. /**********************************************************************
  719.  *
  720.  * fplInit();
  721.  *
  722.  * Initialize a lot of FPL internal structures and references. Returns
  723.  * NULL if anything went wrong!
  724.  *
  725.  *******/
  726.  
  727. void * ASM fplInit(AREG(0) long (*function) (void *),
  728.            /* function handler pointer */
  729.            AREG(1) unsigned long *tags) /* taglist */
  730. {
  731.   struct Data point;
  732.   struct Data *scr;
  733.   void *init;
  734.   scr=&point;
  735.  
  736. #ifdef AMIGA
  737.   /* Store all register before loading index register */
  738.   StoreRegisters(scr);
  739.   geta4();
  740. #endif
  741.  
  742.   init=Init(&point, function, tags);
  743.   if(!init)
  744.     FREEALLA();
  745. #ifdef DEBUGMAIL
  746.   DebugMail(scr, MAIL_FUNCTION, 500, "fplInit");
  747. #endif
  748.   return(init);
  749. }
  750.  
  751. static void * INLINE Init(struct Data *scr,    /* stack oriented */
  752.               long ASM (*function) (AREG(0) void *), 
  753.               unsigned long *tags) /* taglist */
  754. {
  755.   ReturnCode ret;
  756.   char *buffer;
  757.   struct Data *ptr;
  758. #ifdef AMIGA
  759.   long registers[11];
  760.  
  761.   memcpy(registers, scr->registers, sizeof(long)*11);
  762. #endif
  763.   /* Set default that just might get changed in SetTags(); */
  764.  
  765.   memset(scr, 0, sizeof(struct Data)); /* NULLs everything! */
  766.  
  767.   scr->Alloc=DefaultAlloc;
  768.   scr->Dealloc=DefaultDealloc;;
  769.   scr->hash_size=FPL_HASH_SIZE;
  770.   scr->runs=0;
  771.   InitFree(scr); /* init memory caches */
  772.  
  773. #ifdef AMIGA
  774.  
  775.   memcpy(scr->registers, registers, sizeof(long)*11);
  776.  
  777.   scr->stack_size=FPL_MIN_STACK;
  778.   scr->stack_max=FPL_MAX_STACK;
  779.   scr->stack_limit=FPL_MAX_LIMIT;
  780.   scr->stack_margin=FPLSTACK_MINIMUM;
  781. #endif
  782.  
  783.   SetTags(scr, tags); /* read tags and set proper members */
  784.  
  785.   buffer=(char *)MALLOCA(BUF_SIZE);
  786.   if(!buffer)
  787.     /* fail! */
  788.     return(NULL);
  789.  
  790. #ifdef AMIGA
  791. #pragma msg 225 ignore    /* ignore the 225 warnings that occur on the following
  792.                assign! */
  793. #endif
  794.   scr->function=(long ASM (*)(AREG(0) void *))function;
  795.  
  796. #ifdef AMIGA
  797. #pragma msg 225 warning    /* enable the 225 warnings again! */
  798. #endif
  799.  
  800.   scr->buf=buffer;
  801.  
  802. #if defined(AMIGA) && defined(SHARED)
  803.   scr->stack_base=MALLOCA(scr->stack_size);
  804.   if(!scr->stack_base)
  805.     return(NULL);
  806.   scr->intern_stack = (long)scr->stack_base + scr->stack_size;
  807.   Forbid();
  808.   scr->task = FindTask(NULL);  /* get pointer to our task! */
  809.   Permit();
  810. #endif
  811.  
  812.   if(ret=InitHash(scr))
  813.     return(NULL);
  814.  
  815.   ptr=(struct Data *)MALLOCA(sizeof(struct Data));
  816.   if(ptr)
  817.     *ptr=*scr; /* copy the entire structure! */
  818.  
  819.   return((void *)ptr);
  820. }
  821.  
  822. /**********************************************************************
  823.  *
  824.  * fplReset();
  825.  *
  826.  * This function is used to change or add tags to FPL. All tags
  827.  * available for fplFree() is legal. Not changed tags will remain
  828.  * as they were before this call!
  829.  *
  830.  * I had to insert this function since I found out that I wanted to
  831.  * alter the userdata in my application using FPL, and that was hard
  832.  * doing so (nice) without this change.
  833.  * 
  834.  * Library front end to SetTags();
  835.  *
  836.  *****/
  837.  
  838. ReturnCode PREFIX fplReset(AREG(0) struct Data *scr,
  839.                 AREG(1) unsigned long *tags)
  840. {
  841. #ifdef DEBUGMAIL
  842.   DebugMail(scr, MAIL_FUNCTION, 500, "fplReset");
  843. #endif
  844.   if(!scr)
  845.     return FPLERR_ILLEGAL_ANCHOR;
  846.   return SetTags(scr, tags);
  847. }
  848.  
  849.  
  850. /**********************************************************************
  851.  *
  852.  * SetTags();
  853.  *
  854.  * Read the taglist supplied in the second parameter, and set all data
  855.  * according to those.
  856.  *
  857.  *****/
  858.  
  859. static ReturnCode REGARGS
  860. SetTags(struct Data *scr,
  861.         unsigned long *tags)
  862. {
  863.   if(!scr)
  864.     return(FPLERR_ILLEGAL_ANCHOR);
  865.  
  866.   while(tags && *tags) {
  867.     switch(*tags++) {
  868. #ifdef AMIGA
  869. #pragma msg 225 ignore    /* ignore the 225 warnings that occur on the following
  870.                four assigns! */
  871. #endif
  872.     case FPLTAG_INTERVAL:
  873.       scr->interfunc=(long ASM (*)(AREG(0) void *))*tags;
  874.       break;
  875.  
  876.     case FPLTAG_INTERNAL_ALLOC:
  877.       scr->Alloc=(void * ASM (*)(DREG(0) long,
  878.                                  AREG(0) void *))*tags;
  879.       break;
  880.     case FPLTAG_INTERNAL_DEALLOC:
  881.       scr->Dealloc=(void ASM (*)(AREG(1) void *,
  882.                                  DREG(0) long,
  883.                                  AREG(0) void *))*tags;
  884.       break;
  885. #ifdef AMIGA
  886. #pragma msg 225 warning /* enable the 225 warning again for correct program
  887.                checking! */
  888. #endif
  889.  
  890.     case FPLTAG_REREAD_CHANGES:
  891.       scr->flags = BitToggle(scr->flags, FPLDATA_REREAD_CHANGES, *tags);
  892.       break;
  893.  
  894.     case FPLTAG_FLUSH_NOT_IN_USE:
  895.       scr->flags = BitToggle(scr->flags, FPLDATA_FLUSH_NOT_IN_USE, *tags);
  896.       break;
  897.  
  898.     case FPLTAG_KIDNAP_CACHED:
  899.       scr->flags = BitToggle(scr->flags, FPLDATA_KIDNAP_CACHED, *tags);
  900.       break;
  901.  
  902.     case FPLTAG_PREVENT_RUNNING_SAME:
  903.       scr->flags = BitToggle(scr->flags, FPLDATA_PREVENT_RUNNING_SAME, *tags);
  904.       break;
  905.  
  906.     case FPLTAG_HASH_TABLE_SIZE:
  907.       if(*tags>FPL_MIN_HASH)
  908.     scr->hash_size=*tags;
  909.       break;
  910.  
  911.     case FPLTAG_USERDATA:
  912.       scr->userdata=(void *)*tags;
  913.       break;
  914.  
  915.     case FPLTAG_ALLFUNCTIONS:
  916.       scr->flags = BitToggle(scr->flags, FPLDATA_ALLFUNCTIONS, *tags);
  917.       break;
  918.  
  919.     case FPLTAG_NESTED_COMMENTS:
  920.       scr->flags = BitToggle(scr->flags, FPLDATA_NESTED_COMMENTS, *tags);
  921.       break;
  922.  
  923.     case FPLTAG_CACHEALLFILES:
  924.       if(*tags) {
  925.     scr->flags|=FPLDATA_CACHEALLFILES;
  926.     if(*tags == FPLCACHE_EXPORTS)
  927.       scr->flags|=FPLDATA_CACHEEXPORTS;
  928.       } else
  929.     scr->flags &= ~(FPLDATA_CACHEALLFILES|FPLDATA_CACHEEXPORTS);
  930.       break;
  931.  
  932. #ifdef STRING_STACK
  933.     case FPLTAG_STRINGSTACK:
  934.       scr->strings_in_stack_max = (long)*tags;
  935.       if( scr->strings_in_stack_max>0 ) {
  936.         if(scr->stringsstack) {
  937.           FREEA(scr->stringsstack);
  938.         }
  939.         GETMEMA(scr->stringstack, scr->strings_in_stack_max *
  940.                                   sizeof( struct StringStack ));
  941.       }
  942.       break;
  943. #endif
  944.  
  945. #ifdef AMIGA
  946.     case FPLTAG_STACK:
  947.       /* Only change stack if the required size is large enough! */
  948.       if(*tags>FPL_MIN_STACK)
  949.     scr->stack_size=(long)*tags;
  950.       break;
  951.  
  952.     case FPLTAG_MAXSTACK:
  953.       /* Only change this if the required size is large enough! */
  954.       if(*tags>FPL_MIN_STACK)
  955.     scr->stack_max=(long)*tags;
  956.       break;
  957.  
  958.     case FPLTAG_STACKLIMIT:
  959.       /* Only change this if the required size is large enough! */
  960.       if(*tags>FPL_MIN_STACK)
  961.     scr->stack_limit=(long)*tags;      
  962.       break;
  963.  
  964.     case FPLTAG_MINSTACK:
  965.       /* Only change this if the required size is larger than default! */
  966.       if(*tags>FPLSTACK_MINIMUM)
  967.     scr->stack_margin=*tags;
  968.       break;
  969.  
  970.     case FPLTAG_LOCKUSED:
  971.       /* This determines whether to use locked files when executing or not.
  972.      Default is false. */
  973.       scr->flags = BitToggle(scr->flags, FPLDATA_LOCKUSED, *tags);
  974.       break;
  975. #endif
  976.  
  977.     case FPLTAG_IDENTITY:
  978.       /* new from version 9: Host process identifier! */
  979.       scr->identifier = (char *)(*tags);
  980.       break;
  981.       
  982.     case FPLTAG_DEBUG:
  983.       scr->flags = BitToggle(scr->flags, FPLDATA_DEBUG_MODE, *tags);
  984.       break;
  985.       
  986.     case FPLTAG_ERROR_BUFFER:
  987.       scr->error = (char *)(*tags);
  988.       break;
  989.  
  990.     }
  991.     tags++; /* next! */
  992.   }
  993.   return(FPL_OK);
  994. }
  995.  
  996. long REGARGS
  997. BitToggle(long original, /* Original 32 bits */
  998.       long bit,      /* alternate bit pattern */
  999.       long OnOff)    /* Or/And boolean, TRUE==OR, FALSE==AND */
  1000. {
  1001.   if(OnOff)
  1002.     return ( original | bit );
  1003.   else
  1004.     return ( original & ~bit );
  1005. }
  1006.